home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-13 / xvisrc.zip / FLEXBUF.C < prev    next >
C/C++ Source or Header  |  1992-07-28  |  7KB  |  401 lines

  1. /* Copyright (c) 1990,1991,1992 Chris and John Downey */
  2. #ifndef lint
  3. static char *sccsid = "@(#)flexbuf.c    2.2 (Chris & John Downey) 8/27/92";
  4. #endif
  5.  
  6. /***
  7.  
  8. * program name:
  9.     xvi
  10. * function:
  11.     PD version of UNIX "vi" editor, with extensions.
  12. * module name:
  13.     flexbuf.c
  14. * module function:
  15.     Routines for Flexbufs (variable-length FIFO queues).
  16.  
  17.     Some of the access routines are implemented as macros in xvi.h.
  18. * history:
  19.     STEVIE - ST Editor for VI Enthusiasts, Version 3.10
  20.     Originally by Tim Thompson (twitch!tjt)
  21.     Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
  22.     Heavily modified by Chris & John Downey
  23.  
  24. ***/
  25.  
  26. #include "xvi.h"
  27.  
  28. #define FLEXEXTRA    64
  29.  
  30. /*
  31.  * Append a single character to a Flexbuf. Return FALSE if we've run
  32.  * out of space.
  33.  *
  34.  * Note that the f->fxb_chars array is not necessarily null-terminated.
  35.  */
  36. bool_t
  37. flexaddch(f, ch)
  38. register Flexbuf    *f;
  39. int    ch;
  40. {
  41.     if (flexempty(f))
  42.     f->fxb_rcnt = f->fxb_wcnt = 0;
  43.     if (f->fxb_wcnt >= f->fxb_max) {
  44.     if (f->fxb_max == 0) {
  45.         if ((f->fxb_chars = alloc(FLEXEXTRA)) == NULL) {
  46.         return FALSE;
  47.         } else {
  48.         f->fxb_max = FLEXEXTRA;
  49.         }
  50.     } else {
  51.         unsigned newsize = f->fxb_wcnt + FLEXEXTRA;
  52.  
  53.         if ((f->fxb_chars = realloc(f->fxb_chars, newsize)) == NULL) {
  54.         f->fxb_wcnt = f->fxb_max = 0;
  55.         return FALSE;
  56.         } else {
  57.         f->fxb_max = newsize;
  58.         }
  59.     }
  60.     }
  61.     f->fxb_chars[f->fxb_wcnt++] = ch;
  62.     return TRUE;
  63. }
  64.  
  65. /*
  66.  * Return contents of a Flexbuf as a null-terminated string.
  67.  */
  68. char *
  69. flexgetstr(f)
  70. Flexbuf    *f;
  71. {
  72.     if (!flexempty(f) && flexaddch(f, '\0')) {
  73.     --f->fxb_wcnt;
  74.     return &f->fxb_chars[f->fxb_rcnt];
  75.     } else {
  76.     return "";
  77.     }
  78. }
  79.  
  80. /*
  81.  * Remove the first character from a Flexbuf and return it.
  82.  */
  83. int
  84. flexpopch(f)
  85. Flexbuf    *f;
  86. {
  87.     return flexempty(f) ?
  88.     0 : (unsigned char) f->fxb_chars[f->fxb_rcnt++];
  89. }
  90.  
  91. /*
  92.  * Free storage belonging to a Flexbuf.
  93.  */
  94. void
  95. flexdelete(f)
  96. Flexbuf    *f;
  97. {
  98.     if (f->fxb_max > 0) {
  99.     (void) free(f->fxb_chars);
  100.     f->fxb_wcnt = f->fxb_max = 0;
  101.     }
  102. }
  103.  
  104. /*
  105.  * The following routines provide for appending formatted data to a
  106.  * Flexbuf using a subset of the format specifiers accepted by
  107.  * printf(3). The specifiers we understand are currently
  108.  *
  109.  *    %c %d %ld %lu %s %u
  110.  *
  111.  * Field width, precision & left justification can also be specified
  112.  * as for printf().
  113.  *
  114.  * The main advantage of this is that we don't have to worry about the
  115.  * end of the destination array being overwritten, as we do with
  116.  * sprintf(3).
  117.  */
  118.  
  119. static    unsigned    width;
  120. static    unsigned    prec;
  121. static    bool_t        ljust;
  122.  
  123. /*
  124.  * Append a string to a Flexbuf, truncating the string & adding filler
  125.  * characters as specified by the width, prec & ljust variables.
  126.  *
  127.  * The precision specifier gives the maximum field width.
  128.  */
  129. static bool_t
  130. strformat(f, p)
  131. Flexbuf *f;
  132. register char *p;
  133. {
  134.     register int c;
  135.  
  136.     if (width != 0 && !ljust) {
  137.     register unsigned len;
  138.  
  139.     len = strlen(p);
  140.     if (prec != 0 && prec < len)
  141.         len = prec;
  142.     while (width > len) {
  143.         if (!flexaddch(f, ' '))
  144.         return FALSE;
  145.         --width;
  146.     }
  147.     }
  148.  
  149.     while ((c = *p++) != '\0') {
  150.     if (!flexaddch(f, c))
  151.         return FALSE;
  152.     if (width != 0)
  153.         --width;
  154.     if (prec != 0) {
  155.         if (--prec == 0) {
  156.         break;
  157.         }
  158.     }
  159.     }
  160.     while (width != 0) {
  161.     if (!flexaddch(f, ' '))
  162.         return FALSE;
  163.     --width;
  164.     }
  165.     return TRUE;
  166. }
  167.  
  168. /*
  169.  * Given a binary long integer, convert it to a decimal number &
  170.  * append it to the end of a Flexbuf.
  171.  *
  172.  * The precision specifier gives the minimum number of decimal digits.
  173.  */
  174. static bool_t
  175. numformat(f, n, uflag)
  176. Flexbuf    *f;
  177. long    n;
  178. bool_t    uflag;
  179. {
  180.     register char *s;
  181.     register unsigned len;
  182.  
  183.     if (n == 0) {
  184.     /*
  185.      * Special case.
  186.      */
  187.     s = "0";
  188.     len = 1;
  189.     } else {
  190.     static char dstr[sizeof (long) * 3 + 2];
  191.     register unsigned long un;
  192.     int neg;
  193.  
  194.     * (s = &dstr[sizeof dstr - 1]) = '\0';
  195.  
  196.     if (!uflag && n < 0) {
  197.         neg = 1;
  198.         un = -n;
  199.     } else {
  200.         neg = 0;
  201.         un = n;
  202.     }
  203.  
  204.     while (un > 0 && s > &dstr[1]) {
  205.         *--s = (un % 10) + '0';
  206.         un /= 10;
  207.     }
  208.  
  209.     if (neg)
  210.         *--s = '-';
  211.     len = &dstr[sizeof dstr - 1] - s;
  212.     }
  213.  
  214.     while (width > len && width > prec) {
  215.     if (!flexaddch(f, ' '))
  216.         return FALSE;
  217.     --width;
  218.     }
  219.  
  220.     while (prec > len) {
  221.     if (!flexaddch(f, '0'))
  222.         return FALSE;
  223.     --prec;
  224.     if (width > 0)
  225.         --width;
  226.     }
  227.     prec = 0;
  228.     return strformat(f, s);
  229. }
  230.  
  231. /*
  232.  * Main formatting routine.
  233.  */
  234. bool_t
  235. vformat
  236. #ifdef __STDC__
  237.     (Flexbuf *f, register char *format, register va_list argp)
  238. #else
  239.     (f, format, argp)
  240.     Flexbuf        *f;
  241.     register char    *format;
  242.     register va_list    argp;
  243. #endif
  244. {
  245.     register int c;
  246.  
  247.     while ((c = *format++) != '\0') {
  248.     if (c == '%') {
  249.         static char cstr[2];
  250.         bool_t lnflag;
  251.         bool_t zflag;
  252.  
  253.         lnflag = FALSE;
  254.         ljust = FALSE;
  255.         width = 0;
  256.         prec = 0;
  257.         zflag = FALSE;
  258.         if ((c = *format++) == '-') {
  259.         ljust = TRUE;
  260.         c = *format++;
  261.         }
  262.  
  263.         /*
  264.          * Get width specifier.
  265.          */
  266.         if (c == '0') {
  267.         if (ljust)
  268.             /*
  269.              * It doesn't make sense to
  270.              * have a left-justified
  271.              * numeric field with zero
  272.              * padding.
  273.              */
  274.             return FALSE;
  275.         zflag = TRUE;
  276.         c = *format++;
  277.         }
  278.  
  279.         while (c && is_digit(c)) {
  280.         if (width != 0)
  281.             width *= 10;
  282.         width += (c - '0');
  283.         c = *format++;
  284.         }
  285.  
  286.         if (c == '.') {
  287.         /*
  288.          * Get precision specifier.
  289.          */
  290.         while ((c = *format++) != '\0' && is_digit(c)) {
  291.             if (prec != 0)
  292.             prec *= 10;
  293.             prec += (c - '0');
  294.         }
  295.         }
  296.  
  297.         switch (c) {
  298.         case '%':
  299.         cstr[0] = c;
  300.         if (!strformat(f, cstr))
  301.             return FALSE;
  302.         continue;
  303.  
  304.         case 'c':
  305.         cstr[0] = va_arg(argp, int);
  306.         if (!strformat(f, cstr))
  307.             return FALSE;
  308.         continue;
  309.  
  310.         case 'l':
  311.         switch (c = *format++) {
  312.         case 'd':
  313.         case 'u':
  314.             lnflag = TRUE;
  315.             break;
  316.         default:
  317.             /*
  318.              * Syntax error.
  319.              */
  320.             return FALSE;
  321.         }
  322.         /* fall through ... */
  323.  
  324.         case 'd':
  325.         case 'u':
  326.         {
  327.         long n;
  328.  
  329.         if (lnflag)
  330.         {
  331.             n = (c == 'u' ?
  332.                     (long) va_arg(argp, unsigned long) :
  333.                 va_arg(argp, long));
  334.         } else {
  335.             n = (c == 'u' ?
  336.                 (long) va_arg(argp, unsigned int) :
  337.                 (long) va_arg(argp, int));
  338.         }
  339.  
  340.         /*
  341.          * For integers, the precision
  342.          * specifier gives the minimum number
  343.          * of decimal digits.
  344.          */
  345.         if (zflag && prec < width) {
  346.             prec = width;
  347.             width = 0;
  348.         }
  349.         if (!numformat(f, n, (c == 'u')))
  350.             return FALSE;
  351.         continue;
  352.         }
  353.  
  354.         case 's':
  355.         {
  356.         char *sp;
  357.  
  358.         if ((sp = va_arg(argp, char *)) == NULL ||
  359.                         !strformat(f, sp)) {
  360.             return FALSE;
  361.         }
  362.         continue;
  363.         }
  364.  
  365.         default:
  366.         /*
  367.          * Syntax error.
  368.          */
  369.         return FALSE;
  370.         }
  371.     } else if (!flexaddch(f, c)) {
  372.         return FALSE;
  373.     }
  374.     }
  375.     return TRUE;
  376. }
  377.  
  378. /*
  379.  * Front end callable with a variable number of arguments.
  380.  */
  381. /*VARARGS2*/
  382. bool_t
  383. lformat
  384. #ifdef __STDC__
  385.     (Flexbuf *f, char *format, ...)
  386. #else
  387.     (f, format, va_alist)
  388.     Flexbuf    *f;
  389.     char    *format;
  390.     va_dcl
  391. #endif
  392. {
  393.     va_list argp;
  394.     bool_t retval;
  395.  
  396.     VA_START(argp, format);
  397.     retval = vformat(f, format, argp);
  398.     va_end(argp);
  399.     return retval;
  400. }
  401.